﻿package taurus.client;

import java.util.HashMap;
import java.util.Map;

import com.taurus.core.entity.ITObject;
import com.taurus.core.events.Event;
import com.taurus.core.events.EventDispatcher;
import com.taurus.core.events.IEventListener;
import com.taurus.core.util.*;

import taurus.client.io.SocketEngine;


/**
 * 网络核心功能处理类
 * @author daixiwei	daixiwei15@126.com
 *
 */
public class TaurusClient {
	private static final Logger	logger	= Logger.getLogger(TaurusClient.class);
	private int					_id;
	private boolean				_connect;
	private String				_gameId;
	private String				_host;

	private ISocketLayer		_scoket;
	private ThreadManager		_threadManager;

	private EventDispatcher		_dispatcher;
	private Map<Message, ICallback<MessageResponse>> _responseMap;
	volatile boolean			_kill	= false;
	private static int			_tempID;
	private int _protocolCompression=100;
	
	private static int _getValidID() {
		return ++_tempID;
	}

	/**
	 * 
	 * @param host
	 * @param game
	 * @param protocol
	 */
	public TaurusClient(String host, String game, ConnectionProtocol protocol) {
		ISocketLayer socket = null;
		switch (protocol) {
		case Tcp:
			socket = new SocketEngine(this);
			break;
		case Web:
			socket = new HttpClient(host);
			_connect = true;
			break;
		default:
			socket = new SocketEngine(this);
			break;
		}
		__initialize(host, game, socket);
	}

	/**
	 * 
	 * @param host
	 * @param game
	 * @param socket
	 * @param protocol
	 */
	public TaurusClient(String host, String game, ISocketLayer socket) {
		__initialize(host, game, socket);
		
	}

	/**
	 * 添加事件
	 * @param eventType
	 * @param listener
	 */
	public void addEventListener(String eventType, IEventListener listener) {
		_dispatcher.addEventListener(eventType, listener);
	}

	/**
	 * 移除所有事件
	 */
	public void removeAllListener() {
		_dispatcher.removeAllListener();
	}

	/**
	 * 移除指定事件
	 * @param eventType
	 * @param listener
	 */
	public void removeEventListener(String eventType, IEventListener listener) {
		_dispatcher.removeEventListener(eventType, listener);
	}

	private void __initialize(String host, String game, ISocketLayer socket) {
		_dispatcher = new EventDispatcher();
		_responseMap = new HashMap<Message, ICallback<MessageResponse>>();
        _id = _getValidID();
        NetManager.addNetClient(this);
        _host = host;
        _gameId = game;
        _threadManager = new ThreadManager();
        _threadManager.start();
        _scoket = socket;
		_scoket.setOnConnect(new ICallback<SocketCode>() {
			@Override
			public void action(SocketCode code) {
				if (code == SocketCode.Connect)
					_connect = true;
				else
					_connect = false;
				Event evt = new Event(NetClientEvent.Connect);
				evt.setParameter("code", code);
				_dispatcher.dispatchEvent(evt);
			}
		});
		_scoket.setOnEvent(new ICallback<Message>() {
			@Override
			public void action(Message msg) {
				if (_connect) {
					Event evt = new Event(NetClientEvent.OnEvent);
					evt.setParameter("msg", msg);
					_dispatcher.dispatchEvent(evt);
					if (NetManager.debug_print){
                        String str = getProtocol() == ConnectionProtocol.Web ? "WEB" : "TCP";
                        String data_str = msg.useText ? msg.textParam : (msg.param != null ? msg.param.toJson() : "null");
                        logger.debug("Event [" + str + "->" + msg.command + "] data:" + data_str);
                    }
				}
			}
		});
	}

	/**
	 * 连接服务器
	 */
	public void connect() {
		_scoket.connect();
	}
	
	public void connect(ITObject validate)
    {
        _scoket.connect(validate);
    }
	
	/**
	 * Kill net connection.
	 */
	public void killConnection() {
		removeAllListener();
		_responseMap.clear();
		_threadManager.stop();
		_scoket.disconnect();
		_connect = false;
		_kill = true;
	}

	/**
	 * 发送网络消息包
	 * @param msg	消息数据对象
	 */
	protected void send(Message msg) {
		if (msg == null)
			return;
		if (NetManager.debug_print) {
			String str = getProtocol() == ConnectionProtocol.Web ? "WEB" : "TCP";
			String data_str = msg.useText ? msg.textParam : (msg.param != null ? msg.param.toJson() : "null");
			str = "Requst [" + str + "->" + msg.command + "] ->data:" + data_str;
			logger.debug(str);
		}
		if (msg.callback != null) {
			_responseMap.put(msg, msg.callback);
			msg.callback = new ICallback<MessageResponse>() {

				@Override
				public void action(MessageResponse response) {
					ICallback<MessageResponse> callback = _responseMap.get(response.messageData);
					if (callback == null) {
						return;
					}
					if (NetManager.debug_print){
                        String str = getProtocol() == ConnectionProtocol.Web ? "WEB" : "TCP";
                        String data_str = msg.useText ? msg.textParam : (msg.param != null ? msg.param.toJson() : "null");
                        str = "Response [" + str + "->" + msg.command + "] ->result:"+ response.returnCode + " param:" + data_str;
                        logger.debug(str);
                    }
					_responseMap.remove(response.messageData);
					callback.action(response);
				}

			};
		}

		_threadManager.enqueueSend(new ICallback<Message>() {
			@Override
			public void action(Message msg) {
				sendData(msg);
			}
		}, msg);
	}

	
	/**
	 * 发送网络消息包
	 * @param cmd 		网络协议指令Key
	 * @param param		参数
	 * @param callback	网络消息回调
	 * @return
	 */
	public Message send(String cmd, ITObject param, ICallback<MessageResponse> callback) {
		Message msg = new Message();
		msg.useText = false;
		msg.command = cmd;
		msg.param = param;
		msg.callback = callback;
		this.send(msg);
		return msg;
	}
	
	/**
	 * 发送网络消息包
	 * @param cmd 		网络协议指令Key
	 * @param text		JSON 文本
	 * @param callback	网络消息回调
	 * @return
	 */
	public Message sendText(String cmd, String text, ICallback<MessageResponse> callback) {
		Message msg = new Message();
		msg.command = cmd;
		msg.textParam = text;
		msg.callback = callback;
		msg.useText = true;
		this.send(msg);
		return msg;
	}

	/**
	 * 发送数据线程方法
	 * @param message
	 */
	private void sendData(Message msg) {
		_scoket.write(msg);
	}

	/**
	 * 处理事件
	 */
	void processEvent() {
		if(_scoket!=null) {
			_scoket.processEvent();
		}
	}

	/**
	 * 清理响应回调
	 */
	public void clearResponse() {
		_responseMap.clear();
	}

	/**
	 * The net client id
	 * @return
	 */
	public int getId() {
		return _id;
	}
	
	/**
	 * 获取服务地址
	 * @return
	 */
    public String getHost(){
        return _host;
    }

	/**
	 * The curren Game ID
	 * @return
	 */
	public String getGameID() {
		return _gameId;
	}

	/**
	 * 网络是否已连接
	 * @return
	 */
	public boolean isConnected() {
		return _connect;
	}

	/**
	 * 当前网络类型
	 * @return
	 */
	public ConnectionProtocol getProtocol() {
		return _scoket.getProtocol();
	}

	/**
	 * 网络延时
	 * @return
	 */
	public int getAveragePingTime() {
		return _scoket.getAveragePingTime();
	}

	/**
	 * 获取服务器Session字符
	 * @return
	 */
	public String getSession() {
		return _scoket.getSession();
	}

	/**
	 * 设置服务器Session字符
	 * @param session
	 */
	public void setSession(String session) {
		_scoket.setSession(session);
	}
	
	/**
	 * 设置压缩阀值
	 * @param protocolCompression
	 */
	public void setProtocolCompression(int protocolCompression) {
		_protocolCompression = protocolCompression;
	}

	/**
	 * 获取压缩阀值
	 * 
	 * @return
	 */
	public int getProtocolCompression() {
		return _protocolCompression;
	}
    

	public static enum ConnectionProtocol {
		Tcp, Web,
	}

	public static class NetClientEvent {
		public static final String	Connect	= "connect";

		public static final String	OnEvent	= "onevent";
	}
}
